home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Aminet 16
/
Aminet 16 (1996)(GTI - Schatztruhe)[!][Dec 1996].iso
/
Aminet
/
misc
/
emu
/
QDOS2.lha
/
QLsource
/
ROMsrc
/
PAR
/
PAR_asm
Wrap
Text File
|
1994-07-27
|
12KB
|
523 lines
SECTION PAR
INCLUDE '/INC/QDOS_inc'
INCLUDE '/INC/AMIGA_inc'
INCLUDE '/INC/AMIGQDOS_inc'
; ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
; PAR1_asm - parallel device driver
; - last modified 27/07/94
; These are all the necessary parallel port related sources,
; required to implement a QDOS parallel device on the Amiga
; computer.
; Amiga-QDOS sources by Rainer Kowallik
; ...latest changes by Mark J Swift
; ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
; Channel definition block
PAR_TXQL EQU 81 ; Length of transmit buffer
; (odd!)
PAR_DBGQL EQU 2048
PAR_PROT EQU 24 ; EOL Protocol, -ve RAW
; 0 CR/LF, 1 CR, 2 LF
PAR_EOF EQU 26 ; EOF (CLOSE) protocol
; -ve none, 0 FormFeed
PAR_TXD EQU 28 ; last transmitted character
PAR_FLGS EQU 30 ; Bit 0 0 = busy
; 1 = ready
PAR_TXQ EQU 32 ; Transmit queue header
PAR_END EQU PAR_TXQ+Q_QUEUE+PAR_TXQL+1 ; total memory
; ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
; ROM header
BASE:
dc.l $4AFB0001 ; ROM recognition code
dc.w 0
dc.w ROM_START-BASE
dc.b 0,36,'Amiga-QDOS PAR device driver v1.07 ',$A
; ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
; start of ROM code
ROM_START:
movem.l d0-d2/a0-a3,-(a7)
; --------------------------------------------------------------
; allocate memory for parallel device variables
move.l #PV_LEN,d1
moveq #MT.ALCHP,d0
moveq #0,d2
trap #1
tst.l d0
bne ROM_EXIT
; --------------------------------------------------------------
; address of PAR variables
move.l a0,AV.PARV
move.l a0,a3
; --------------------------------------------------------------
; enter supervisor mode and disable interrupts
trap #0
ori.w #$0700,sr ; disable interrupts
; --------------------------------------------------------------
; link a custom routine into level 7 interrupt server
lea AV.LVL7link,a1
lea PV.LVL7link(a3),a2
move.l (a1),(a2)
move.l a2,(a1)
lea MY_LVL7(pc),a1
move.l a1,$04(a2)
; --------------------------------------------------------------
; routines necessary for device driver
lea PAR_IO(pc),a2 ; Input/Output routine
move.l a2,SV_AIO(a3)
lea PAR_OPEN(pc),a2 ; OPEN routine
move.l a2,SV_AOPEN(a3)
lea PAR_CLOSe(pc),a2 ; CLOSE routine
move.l a2,SV_ACLOS(a3)
; --------------------------------------------------------------
; routines necessary for IO.SERIO. (used by PAR I/O routine)
lea ERR_BP(pc),a2 ; test for pending input
move.l a2,PV.PEND(a3) ; (not provided)
lea ERR_BP(pc),a2 ; fetch byte
move.l a2,PV.FBYTE(a3) ; (not provided)
lea PAR_SBYT(pc),a2 ; send byte
move.l a2,PV.SBYTE(a3)
move.w #$4E75,PV.RTS(A3) ; RTS instruction at $34
; --------------------------------------------------------------
; set up hardware
bsr.s INIT_HW
; --------------------------------------------------------------
; link in device driver
lea SV_LIO(a3),a0 ; link address
moveq #MT.LIOD,d0 ; link in IO device driver
trap #1
; -------------------------------------------------------------
; link in external interrupt to act on port free
lea XINT_SERv(pc),a2 ; address of routine
move.l a2,SV_AXINT(a3)
lea SV_LXINT(a3),a0
moveq #MT.LXINT,d0
trap #1
; -------------------------------------------------------------
; link in poll interrupt to re-enable parallel send
lea POLL_SERv(pc),a2 ; address of routine
move.l a2,SV_APOLL(a3)
lea SV_LPOLL(a3),a0
moveq #MT.LPOLL,d0
trap #1
; --------------------------------------------------------------
; enable interrupts and re-enter user mode
andi.w #$D8FF,sr
; --------------------------------------------------------------
ROM_EXIT:
movem.l (a7)+,d0-d2/a0-a3
rts
; ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
; set up hardware
INIT_HW:
movem.l d7/a3,-(a7)
move.l AV.PARV,a3 ; address of PAR variables
move.b CIAA_ICR,d7 ; read & clear CIA-A ICR
or.b AV.CIAA_ICR,d7
bclr #4,d7 ; clear FLAG bit
move.b d7,AV.CIAA_ICR ; store for another program
move.w #%0000000000001000,INTREQ ; clear and enable
move.w #%1000000000001000,INTENA ; CIA-A interrupts
move.b #%10010000,CIAA_ICR ; enable FLAG interrupt
ori.b #%00010000,AV.CIAA_MSK ; take note
MOVE.B #$FF,CIAA_DDRB ; set DDRB to all output
move.l PV.PARTQ(a3),d7 ; address of transmit Q
beq.s INIT_HWX ; exit if Q doesn't exist
move.l d7,a3
bset #0,1+PAR_FLGS-PAR_TXQ(a3) ; port ready
INIT_HWX:
movem.l (a7)+,d7/a3
rts
; ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
; poll interrupt server for parallel port.
; restarts interrupts by sending a byte.
POLL_SERv:
bsr PAR_SEND ; if port ready, send byte
POLL_X:
rts
; ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
; external interrupt server
XINT_SERv:
movem.l d7/a0,-(a7)
move.w INTENAR,d7 ; read interrupt enable reg
btst #3,d7 ; branch if ints not on
beq XINT_OTHer
move.w INTREQR,d7 ; read interrupt request reg
btst #3,d7 ; branch if from CIA-A or
bne CIAA_SERv ; expansion ports
; --------------------------------------------------------------
; otherwise let another external interrupt server handle it
XINT_OTHer:
movem.l (a7)+,d7/a0
rts
; ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
; Interrupt from CIA-A or expansion port
CIAA_SERv:
move.b CIAA_ICR,d7 ; read CIA-A ICR
or.b AV.CIAA_ICR,d7
move.b d7,AV.CIAA_ICR ; store for another program
bclr #4,d7 ; port ready? (FLAG bit=1)
beq XINT_OTHer ; no
; ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
; External interrupt server for acting on par port ready
; (CIAA FLAG bit=1).
PAR_RDY:
move.b d7,AV.CIAA_ICR
and.b AV.CIAA_MSK,d7 ; don't clear INTREQ if
bne.s PAR_RDY0 ; other CIAA ints occured
move.w #%0000000000001000,INTREQ ; clear interrupts
; -------------------------------------------------------------
PAR_RDY0:
move.l AV.PARV,a0 ; address of PAR variables
move.l PV.PARTQ(a0),d7 ; address of transmit Q
beq.s XINT_EXIt ; exit if Q doesn't exist
move.l d7,a0
bset #0,1+PAR_FLGS-PAR_TXQ(a0) ; port ready
bsr PAR_SEND
; -------------------------------------------------------------
XINT_EXIt:
bra XINT_OTHer
; ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
; write next byte from queue to parallel port
PAR_SEND:
movem.l d1/d7/a2-a4,-(a7)
moveq #ERR.NC,d0 ; assume no can do
move.l AV.PARV,a3 ; address of PAR variables
move.l PV.PARTQ(a3),d1 ; address of transmit Q
beq PAR_S_X ; exit if Q doesn't exist
move.l d1,a2
btst #0,1+PAR_FLGS-PAR_TXQ(a2) ; port ready?
beq.s PAR_S_X
btst #0,CIAB_PRA ; printer busy?
bne.s PAR_S_X
btst #1,CIAB_PRA ; paper out?
bne.s PAR_S_X
btst #2,CIAB_PRA ; printer select?
beq.s PAR_S_X
moveq #0,d1
move.w IO.QOUT,a4
jsr (a4) ; get byte d1 from queue a2
tst.l d0
bne.s PAR_S_X ; exit if error
bclr #0,1+PAR_FLGS-PAR_TXQ(a2) ; port busy
move.b CIAA_ICR,d7 ; read CIA-A ICR
or.b AV.CIAA_ICR,d7
bclr #4,d7 ; clear FLAG bit
move.b d7,AV.CIAA_ICR ; store for another program
move.w #%0000000000001000,INTREQ ; clear interrupts
move.b d1,CIAA_PRB ; write data to par port
PAR_S_X:
movem.l (a7)+,d1/d7/a2-a4
rts
; ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
; Here we start with the parallel interface. Although it would
; be possible to read from the hardware, I first write this
; driver for output only.
; I'm following the example from the advanced user guide to
; avoid any problems, and get the whole thing to work as quickly
; as possible!
; Rainer Kowallik
PAR_OPEN:
suba.w #4,a7 ; room for 5 words on
movea.l a7,a3 ; stack.
move.w IO.NAME,a4 ; decode device name
JSR (A4)
BRA.S PAR_O_X ; not found
BRA.S PAR_O_X ; bad device name
BRA.S PAR_O_CHK ; OK, name was PAR_
dc.w 3 ; length of device name
dc.b 'PAR',0 ; definition is PAR
dc.w 2 ; 2 parameters
dc.w 4 ; char value, 4 options
dc.b 'RNCL' ; eol protocol
dc.w 1 ; char value, 2 options
dc.b 'F',0 ; eof protocol
; --------------------------------------------------------------
PAR_O_X:
adda.w #4,a7
ANDI.W #$F8FF,SR
RTS
; --------------------------------------------------------------
PAR_O_CHK:
move.l AV.PARV,a3 ; address of PAR variables
move.l PV.PARTQ(a3),d0 ; address set?
beq.s PAR_O_CHK1 ; no queue, no chan def blk
movea.l d0,a0
suba.w #PAR_TXQ,a0 ; addrs of old chan def blk
bclr #7,PAR_TXQ(a0) ; output queue empty?
bne.s PAR_O_CHK2 ; yes, so continue
bra.s PAR_O_IU ; no, so exit with error
PAR_O_CHK1:
move.w #(PAR_END),d1 ; allocate chan def block
move.w MM.ALCHP,a4 ; for first time
JSR (A4)
bne.s PAR_O_X ; exit if error occured
moveq #PAR_TXQL,d1 ; length of transmit queue
lea PAR_TXQ(a0),a2 ; address of transmit queue
move.w IO.QSET,a4 ; set up queue (not used
jsr (a4) ; before
move.l AV.PARV,a3 ; address of PAR variables
move.l a2,PV.PARTQ(a3)
PAR_O_CHK2:
move.w (a7),PAR_PROT(a0) ; store handshake, protocol
move.w 2(a7),PAR_EOF(a0) ; store EOF protocol
subq.w #2,PAR_PROT(a0) ; -ve raw : 0 CR/LF : 1 CR : 2 LF
subq.w #1,PAR_EOF(a0) ; -ve none : 0 FF : CTRL-Z
bset #0,1+PAR_FLGS(a0) ; set 'port ready' flag
; --------------------------------------------------------------
PAR_O_OK:
moveq #ERR.OK,d0 ; signal "no error"
bra PAR_O_X
; --------------------------------------------------------------
PAR_O_NF:
moveq #ERR.NF,d0 ; not found
bra PAR_O_X
; --------------------------------------------------------------
PAR_O_IU:
moveq #ERR.IU,d0 ; in use
bra PAR_O_X
; --------------------------------------------------------------
PAR_CLOSe:
tst.b 1+PAR_EOF(a0)
blt.s PAR_C2 ; cont if no eof protocol
move.w #12,d1 ; send Form Feed
PAR_CLUP:
bsr PAR_SBOK
cmp.w #ERR.NC,d0
beq.s PAR_CLUP
PAR_C2:
lea PAR_TXQ(a0),a2
move.w IO.QEOF,a4 ; put EOF marker in queue
jsr (a4)
moveq #ERR.OK,d0 ; signal "no errors"
rts
; --------------------------------------------------------------
PAR_IO:
CMP.B #$7,D0 ; trap file operations
BHI ERR_BP
pea PV.PEND(a3) ; pretend call just before
move.w IO.SERIO,a4
JMP (A4)
; --------------------------------------------------------------
PAR_SBYT:
lea PAR_TXQ(a0),a2
move.l d1,d3
move.w IO.QTEST,a4
jsr (a4)
move.l d3,d1
cmpi.w #ERR.EF,d0
beq.s PAR_SB4
moveq #ERR.OK,d0
cmpi.w #$6,d2 ; reasonable space in Q?
bge.s PAR_SB5
moveq #ERR.NC,d0
PAR_SB4:
rts
PAR_SB5:
move.b 1+PAR_TXD(a0),d3 ; remember old TX code
move.b d1,1+PAR_TXD(a0) ; save new TX code
tst.b 1+PAR_PROT(a0)
blt.s PAR_SBOK ; branch if no eol protocol
cmpi.b #$0A,d1 ; Line Feed?
beq.s PAR_SB1
cmpi.b #$0D,d1 ; Carriage Return?
bne.s PAR_SBOK ; branch if neither
PAR_SB1:
cmpi.b #$0A,d3 ; Line Feed?
beq.s PAR_SB2
cmpi.b #$0D,d3 ; Carriage Return?
bne.s PAR_SB3
PAR_SB2:
cmp.b d1,d3
beq.s PAR_SB3
move.b #$FF,1+PAR_TXD(a0) ; ignore LF in CR/LF couple
moveq #ERR.OK,d0
rts
PAR_SB3:
tst.b 1+PAR_PROT(a0)
beq.s PAR_SB6 ; branch if CR/LF protocol
cmp.b #2,1+PAR_PROT(a0)
beq.s PAR_SB7 ; branch if LF
moveq #$0D,d1 ; else use CR
bra.s PAR_SBOK
PAR_SB6:
moveq #$0D,d1
bsr PAR_SBOK
PAR_SB7:
moveq #$0A,d1
PAR_SBOK:
lea PAR_TXQ(a0),a2
move.w IO.QIN,a4 ; put byte d1 into queue a2
jsr (a4)
rts
; ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
ERR_OK:
moveq #ERR.OK,d0 ; "no error"
rts
; ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
ERR_NC:
moveq #ERR.NC,d0 ; "not complete"
rts
; ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
ERR_BP:
moveq #ERR.BP,d0 ; "bad parameter"
rts
; ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
; Custom LVL7 routine to initialise hardware
MY_LVL7:
bsr INIT_HW
subq.l #4,a7
movem.l a3,-(a7)
move.l AV.PARV,a3
move.l PV.LVL7link(a3),a3
move.l 4(a3),4(a7) ; address of next routine
movem.l (a7)+,a3
rts
; ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
END